package com.homer.commons.sscpprotocol.server.impl;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.InetSocketAddress;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.homer.commons.sscpprotocol.server.base.AbstractMessage;
import com.homer.commons.sscpprotocol.server.servlet.ServletContext;
import com.homer.commons.sscpprotocol.server.servlet.SscpServletRequest;

public class SscpRequestImpl extends AbstractMessage implements
		SscpServletRequest {
	private static final long serialVersionUID = -940833727168119141L;

	// private String sourceId;
	// private String destId;
	//
	private byte sync_head;

	private byte key;
	private byte[] mainDeviceID;
	private byte[] slaveDevideID;

	private byte commandLength;

	private byte sync_end;

	private byte[] contentBytes = new byte[0];
	private Charset charset = Charset.defaultCharset();
	private transient String cachedContent;
	private transient Charset cachedContentCharset;
	private ByteArrayInputStream inputStream;
	private static final Pattern PATTERN = Pattern
			.compile("<Param\\s*Name=\"(.*)\"\\s*Value=\"(.*)\"");
	private Map<String, String[]> params;
	private List<String> paramNames;
	private Map<String, Object> attributes;
	private String forward;
	private ServletContext servletContext;
	private InetSocketAddress remoteAddress;
	
	
	private byte[] status;
	private byte[] votage;
	private byte[] rssi;
	
	

	public byte[] getStatus() {
		return status;
	}

	public void setStatus(byte[] status) {
		this.status = status;
	}

	public byte[] getVotage() {
		return votage;
	}

	public void setVotage(byte[] votage) {
		this.votage = votage;
	}

	public byte[] getRssi() {
		return rssi;
	}

	public void setRssi(byte[] rssi) {
		this.rssi = rssi;
	}

	public InetSocketAddress getRemoteAddress() {
		return this.remoteAddress;
	}

	public void setRemoteAddress(InetSocketAddress remoteAddress) {
		this.remoteAddress = remoteAddress;
	}

	// public String getSourceId() {
	// return this.sourceId;
	// }
	//
	// public void setSourceId(String sourceId) {
	// this.sourceId = sourceId;
	// }
	//
	// public String getDestId() {
	// return this.destId;
	// }
	//
	// public void setDestId(String destId) {
	// this.destId = destId;
	// }

	

	public byte[] getContentBytes() {
		return this.contentBytes;
	}

	public byte getSync_head() {
		return sync_head;
	}

	public void setSync_head(byte sync_head) {
		this.sync_head = sync_head;
	}

	public byte getKey() {
		return key;
	}

	public void setKey(byte key) {
		this.key = key;
	}

	public byte[] getMainDeviceID() {
		return mainDeviceID;
	}

	public void setMainDeviceID(byte[] mainDeviceID) {
		this.mainDeviceID = mainDeviceID;
	}

	public byte[] getSlaveDevideID() {
		return slaveDevideID;
	}

	public void setSlaveDevideID(byte[] slaveDevideID) {
		this.slaveDevideID = slaveDevideID;
	}

	public byte getCommandLength() {
		return commandLength;
	}

	public void setCommandLength(byte commandLength) {
		this.commandLength = commandLength;
	}

	public byte getSync_end() {
		return sync_end;
	}

	public void setSync_end(byte sync_end) {
		this.sync_end = sync_end;
	}

	public void setContentBytes(byte[] content) {
		this.contentBytes = content;
	}

	public void setEncoding(String encoding) {
		this.charset = Charset.forName(encoding);
	}

	public String getEncoding() {
		return this.charset.name();
	}

	public String getContent() {
		if ((this.cachedContent != null)
				&& (this.cachedContentCharset == this.charset))
			return this.cachedContent;
		try {
			this.cachedContent = new String(getContentBytes(),
					this.charset.name());
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		this.cachedContentCharset = this.charset;
		return this.cachedContent;
	}

	public synchronized InputStream getInputStream() {
		if (this.inputStream == null) {
			this.inputStream = new ByteArrayInputStream(getContentBytes());
		}
		return this.inputStream;
	}

	public void setServletContext(ServletContext servletContext) {
		this.servletContext = servletContext;
	}

	public ServletContext getServletContext() {
		return this.servletContext;
	}

	public String getParameterValue(String name) {
		extractParams(false);
		String[] values = (String[]) this.params.get(name);
		if (values == null) {
			return null;
		}
		if (values.length == 0) {
			return "";
		}
		return values[0];
	}

	public String[] getParameterValues(String name) {
		extractParams(false);
		return (String[]) this.params.get(name);
	}

	public List<String> getParameterNames() {
		extractParams(false);
		return this.paramNames;
	}

	public void clearAttributes() {
		if (this.attributes != null)
			this.attributes.clear();
	}

	public Object getAttribute(String name) {
		return this.attributes == null ? null : this.attributes.get(name);
	}

	public Object removeAttribute(String name) {
		return this.attributes == null ? null : this.attributes.remove(name);
	}

	public synchronized void setAttribute(String name, Object value) {
		if (this.attributes == null) {
			this.attributes = new HashMap();
		}
		this.attributes.put(name, value);
	}

	public void forwardTo(String forward) {
		this.forward = forward;
	}

	public String getFoward() {
		return this.forward;
	}

	public String toString() {
		return getSync_head() + "; key=" + getKey()
				+ "; commandLength=" + getCommandLength() + "; content="
				+ getContent();
	}

	public void copyTo(SscpRequestImpl processedResquest) {
		processedResquest.setContentBytes(getContentBytes());
		processedResquest.setEncoding(getEncoding());
		processedResquest.setKey(getKey());
		processedResquest.setMainDeviceID(getMainDeviceID());
		processedResquest.setSync_head(getSync_head());
		processedResquest.setCommandLength(getCommandLength());
		processedResquest.setSlaveDevideID(getSlaveDevideID());
		processedResquest.setSync_end(getSync_end());	
	}

	private void extractParams(boolean force) {
		if ((!force) && (this.params != null)) {
			return;
		}
		Map params = new HashMap();
		ArrayList paramNames = new ArrayList();
		int begin = getContent().indexOf("<Params>");
		if (begin != -1) {
			int end = getContent().indexOf("</Params>", begin) + 1;
			Matcher matcher = PATTERN.matcher(getContent().subSequence(begin,
					end));
			while (matcher.find()) {
				String name = matcher.group(1);
				String value = matcher.group(2);
				if (!paramNames.contains(name)) {
					paramNames.add(name);
				}
				String[] values = (String[]) params.get(name);
				if (values == null) {
					params.put(name, new String[] { value });
				} else {
					String[] values2 = new String[values.length + 1];
					for (int i = 0; i < values.length; i++) {
						values2[i] = values[i];
					}
					values2[values.length] = value;
					params.put(name, values2);
				}
			}
		}
		this.params = params;
		this.paramNames = paramNames;
	}

}
